#include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <iostream>

using namespace std;
using namespace Assimp;

void WatchMaterials(aiMaterial **Materials, unsigned int NumMaterials)
{
    cout << "materials :: " << NumMaterials << endl;

    for (unsigned int i = 0; i < NumMaterials; ++i)
    {
        cout << "NumProperties::" << Materials[i]->mNumProperties << endl;
    }
}

void WatchMeshes(aiMesh **Meshes, unsigned int NumMeshes)
{
    cout << "meshes :: " << NumMeshes << endl;

    for (unsigned int i = 0; i < NumMeshes; ++i)
    {
        if (Meshes[i]->HasBones())
            cout << "has bones" << endl;

        if (Meshes[i]->HasFaces())
        {
            cout << "has faces:: " << Meshes[i]->mNumFaces << endl;
        }

        if (Meshes[i]->HasNormals())
        {
            cout << "has uv:: " << Meshes[i]->mNumUVComponents << endl;
        }

        if (Meshes[i]->HasPositions())
        {
            cout << "has position " << endl;
        }

        if (Meshes[i]->HasTangentsAndBitangents())
        {
            cout << "has tangents... " << endl;
        }

        if (Meshes[i]->HasTextureCoords(aiTextureType_AMBIENT))
        {
            cout << "has ambient" << endl;
        }
    }
}

void ParseMaterial(aiMaterial *material)
{
    // for (unsigned int i = 0; i < material->mNumProperties; ++i)
    // {
    //     cout << material->mProperties[i]->mKey.C_Str() << endl;
    // }
    auto index = material->GetTextureCount(aiTextureType_NORMALS);
    cout << "diffuse: " << index << endl;
    aiString path;
    material->GetTexture(aiTextureType_NORMALS, index, &path);
    cout << "file: " << path.C_Str() << endl;
}

void ParseMesh(aiMesh *mesh, const aiScene *scene)
{
    cout << "vertices: " << mesh->mNumVertices << endl;

    unsigned index = mesh->mMaterialIndex;
    if (index < scene->mNumMaterials)
        ParseMaterial(scene->mMaterials[index]);

    if (mesh->HasVertexColors(0))
        cout << "has red color" << endl;
    if (mesh->HasTextureCoords(0))
        cout << "has texture coords" << endl;
}

/**
 * @note 从RootNode开始,由许多node构成scene
 * @note node指向单个或多个mesh,通过下标在scene->Meshes中引用对应的mesh
 */
void TraversalNode(aiNode *node, const aiScene *scene)
{
    cout << node->mName.C_Str() << "\t"
         << " children:: " << node->mNumChildren << endl;

    for (unsigned int i = 0; i < node->mNumMeshes; ++i)
    {
        cout << "mesh index " << node->mMeshes[i] << endl;
        ParseMesh(scene->mMeshes[node->mMeshes[i]], scene);
    }

    for (unsigned int i = 0; i < node->mNumChildren; ++i)
        TraversalNode(node->mChildren[i], scene);
}

int main(void)
{
    Importer importer;

    // 创建默认日志工具,显示详细信息,输出到终端
    DefaultLogger::create("", Logger::VERBOSE, aiDefaultLogStream_STDOUT);

    const aiScene *scene =
        importer.ReadFile("../resource/3ds.3DS", aiProcess_CalcTangentSpace | aiProcess_Triangulate |
                                                     aiProcess_JoinIdenticalVertices | aiProcess_SortByPType);

#if 0
    if (nullptr == scene)
    {
        DefaultLogger::get()->error(importer.GetErrorString());
        return -1;
    }

    if (scene->HasCameras())
    {
        DefaultLogger::get()->info("has cameras!");
    }

    if (scene->HasLights())
    {
        DefaultLogger::get()->info("has lights!");
    }

    if (scene->HasMaterials())
    {
        DefaultLogger::get()->info("has materials!");
        WatchMaterials(scene->mMaterials, scene->mNumMaterials);
    }

    if (scene->HasMeshes())
    {
        DefaultLogger::get()->info("has meshes!");
        WatchMeshes(scene->mMeshes, scene->mNumMeshes);
    }

    if (scene->HasTextures())
    {
        DefaultLogger::get()->info("has textures!");
    }
#endif

    TraversalNode(scene->mRootNode, scene);

    // 关闭日志
    DefaultLogger::kill();

    return 0;
}